package com.ynding.common.easypoi.model;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.Code128Writer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * <p> zxing 条码工具类</p>
 *
 * @author ynding
 * @version 2021/8/14
 **/
@Slf4j
public class BarcodeZxingUtil {

    /**
     * 生成条形码
     *
     * @param content
     * @param width
     * @param height
     * @return
     * @throws Exception
     */
    public static String getBarCode(String content, int width, int height) throws WriterException, IOException {
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.MARGIN, 0);

        int realWidth = getBarCodeNoPaddingWidth(width, content, width);

        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_128, realWidth, height, hints);
        int width2 = bitMatrix.getWidth();
        int height2 = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width2, height2, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width2; x++) {
            for (int y = 0; y < height2; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000
                        : 0xFFFFFFFF);
            }
        }
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(image, "png", os);

        BASE64Encoder encoder = new BASE64Encoder();
        return "data:image/png;base64," + encoder.encode(os.toByteArray());
    }

    /**
     * 获取条形码流
     *
     * @param content
     * @param width
     * @param height
     * @return
     * @throws WriterException
     * @throws IOException
     */
    public static ByteArrayOutputStream getBarCodeStream(String content, int width, int height) throws WriterException, IOException {
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.MARGIN, 1);
        int realWidth = getBarCodeNoPaddingWidth(width, content, width);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.CODE_128, realWidth, height, hints);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(MatrixToImageWriter.toBufferedImage(bitMatrix), "png", os);
        return os;
    }

    /**
     * @param expectWidth
     * @param contents
     * @param maxWidth
     * @return
     */
    private static int getBarCodeNoPaddingWidth(int expectWidth, String contents, int maxWidth) {
        boolean[] code = new Code128Writer().encode(contents);

        int inputWidth = code.length;

        double outputWidth = (double) Math.max(expectWidth, inputWidth);
        double multiple = outputWidth / inputWidth;

        //优先取大的
        int returnVal = 0;
        int ceil = (int) Math.ceil(multiple);
        if (inputWidth * ceil <= maxWidth) {
            returnVal = inputWidth * ceil;
        } else {
            int floor = (int) Math.floor(multiple);
            returnVal = inputWidth * floor;
        }

        return returnVal;
    }


    public static void main(String[] args) throws IOException, WriterException {
        String text = "https://www.baiduxTWpneE5UTXlNREkyT0RrPQ==";
        String logoPath = null;
        String destPath = "D:\\";
        System.out.println(getBarCode(text, 1000, 200));
    }
}
